﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;

namespace EditoneLib.Serialization
{
    [DataContract(Namespace = "http://editone.app/v1")]
    [KnownType(typeof(TrackColor))]
    public class Track : IEditoneSerializable
    {
        public IEditoneSerializer Serializer { protected get; set; }

        [DataMember]
        public string Name { get; set; }

        [DataMember]
        public TrackColor Color { get; set; }

        [DataMember]
        public string TypeName { get; set; }

        [DataMember]
        public Dictionary<string, dynamic> Properties { get; set; }

        [DataMember]
        public IEnumerable<Clip> Clips { get; set; }
       
        public ITrack DelegatedTrack
        {
            get
            {
                var track = CreateTrack(TypeName);

                track.Name = Name;
                track.Color = Color;

                // Set properties
                foreach (var prop in GetTrackProperties(TypeName))
                {
                    if (Properties.ContainsKey(prop.Name))
                    {
                        prop.SetValue(track, Properties[prop.Name]);
                    }
                }

                // Add clips
                foreach (var clip in Clips)
                {
                    clip.Serializer = Serializer;
                    track.Add(clip.Offset, clip.DelegatedClip);
                }

                return track;
            }
            set
            {
                Name = value.Name;
                Color = value.Color;
                TypeName = value.GetType().FullName;

                // Assign properties outside of ITrack
                Properties = new Dictionary<string, dynamic>();
                foreach (var prop in GetTrackProperties(TypeName))
                {
                    Properties[prop.Name] = prop.GetValue(value);
                }

                // Add clips
                Clips = value.Select((kvp) =>
                {
                    var clip = new Clip() {Serializer = Serializer, Offset = kvp.Key};
                    clip.DelegatedClip = kvp.Value;
                    return clip;
                });
            }
        }

        public static ITrack CreateTrack(string typeName)
        {
            ITrack track = Activator.CreateInstance(Type.GetType(typeName)) as ITrack;

            return track;
        }

        private IEnumerable<PropertyInfo> GetTrackProperties(string typeName)
        {
            return Type.GetType(typeName).GetRuntimeProperties()
                .Where((prop) =>
                    prop.CanRead && prop.CanWrite
                    && prop.GetIndexParameters().Length == 0
                    && typeof (ITrack).GetRuntimeProperty(prop.Name) == null
                );
        }

    }
}
